package org.nightknight.satobee.core;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class UDPServer {

    private final String login = "Hello, I'm login just now";
    private final String alive = "Hello, I'm still alive";
    private final String refresh = "Hello, who is online";
    private final String response = "Hello, I'm online";
    private final String logout = "Hello, I'm going to logout";
    private DatagramSocket listenSocket = null;
    private DatagramSocket sendSocket = null;
    private int port = 8199;
    private String url = "255.255.255.255";
    private List<IUsrFndListener> usrFndListeners = new ArrayList<IUsrFndListener>();
    private List<IUsrOutListener> usrOutListeners = new ArrayList<IUsrOutListener>();

    public UDPServer() {
        try {
            this.listenSocket = new DatagramSocket(port);
            this.sendSocket = new DatagramSocket();

            //登录后应当通知网络，自己上线了
            this.login();

            //监听网络
            (new Thread() {

                @Override
                public void run() {
                    while (true) {
                        try {
                            byte[] buf = new byte[256];

                            DatagramPacket packet = new DatagramPacket(buf, buf.length);
                            listenSocket.receive(packet);

                            packetDispatch(packet);
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            Logger.getLogger(UDPServer.class.getName()).log(Level.SEVERE, null, e);
                        }
                    }
                }
            }).start();

            //每过10s向网络中发送在线信息
            (new Thread() {

                @Override
                public void run() {
                    while (true) {
                        try {
                            Thread.sleep(10000);

                            sendAlive();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            Logger.getLogger(UDPServer.class.getName()).log(Level.SEVERE, null, e);
                        }
                    }
                }
            }).start();
        } catch (SocketException e) {
            // TODO Auto-generated catch block
            Logger.getLogger(UDPServer.class.getName()).log(Level.SEVERE, null, e);
        }
    }

    /**
     * 通过udp发送消息
     * @param message
     */
    public void send(String message) {
        byte[] buf = new byte[256];
        try {
            DatagramPacket packet = new DatagramPacket(buf, buf.length,
                    InetAddress.getByAddress(url.getBytes()), port);
            sendSocket.send(packet);
        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            Logger.getLogger(UDPServer.class.getName()).log(Level.SEVERE, null, e);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            Logger.getLogger(UDPServer.class.getName()).log(Level.SEVERE, null, e);
        }
    }

    /**
     * 当用户首次登录该软件时会出发的操作
     */
    public final void login() {
        this.send(login);
    }

    /**
     * 向网络中广播，确认自己在线
     */
    public void sendAlive() {
        this.send(alive);
    }

    /**
     * 向网络中回复收到的信息
     */
    public void sendResponse() {
        this.send(response);
    }

    /**
     * 供用户主动刷新列表
     */
    public void refresh() {
        this.send(refresh);
    }

    /**
     * 检查数据报文件，并转发
     * @param packet
     */
    public void packetDispatch(DatagramPacket packet) {
        String message = new String(packet.getData());

        if (logout.equals(message)) {
            Contact contact = new Contact(packet.getAddress());
            this.fireIUsrOutListener(contact);
        } else {
            if (login.equals(message) || refresh.equals(message)) {
                this.sendResponse();
            }

            fireIUsrFndListener(new Contact(packet.getAddress()));
        }
    }

    public final void addIUsrFndListener(IUsrFndListener listener) {
        this.usrFndListeners.add(listener);
    }

    public void removeIUsrFndListener(IUsrFndListener listener) {
        this.usrFndListeners.remove(listener);
    }

    public void fireIUsrFndListener(Contact contact) {
        for (IUsrFndListener listener : usrFndListeners) {
            listener.userFound(contact);
        }
    }

    public final void addIUsrOutListener(IUsrOutListener listener) {
        this.usrOutListeners.add(listener);
    }

    public void removeIUsrOutListener(IUsrOutListener listener) {
        this.usrOutListeners.remove(listener);
    }

    public void fireIUsrOutListener(Contact contact) {
        for (IUsrOutListener listener : usrOutListeners) {
            listener.userLogout(contact);
        }
    }
}
